#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ioport.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/cacheflush.h>

#define MAJOR_NUMBER     241
#define MODULE_NAME      "buzzer"
#define BUZZER_REG_BASE  na_buzzer_0

static int buzzer_MjNumber = MAJOR_NUMBER;

typedef struct buzzer {
	u32 freq: 24,
	    time:  8;
} BUZZER_REG ;

u32 buzzer_base;

int buzzer_Open(struct inode *inode, struct file *filp) {
	
	printk("buzzer Open\n");
	return 0;
}


ssize_t buzzer_Read (struct file *filp, char *buf, size_t count,loff_t *f_pos) 
{
	u32 reg;
	int retval = 0;
	
	reg = readl(buzzer_base);
	if(copy_to_user((void *)buf, &reg, sizeof(reg))) {
		printk("buzzer_read error\n");
		retval = -EFAULT;
		goto fail;
	}
	
	return 0;
	
fail:
	return retval;

}

ssize_t buzzer_Write (struct file *filp, const char *buf, size_t count,loff_t *f_pos) 
{
	u32 reg;
	int retval = 0;
	
	if(copy_from_user(&reg, (void *)buf, sizeof(reg))){
		printk("buzzer_write error\n");
		retval = -EFAULT;
		goto fail;
	}
	writel(reg, buzzer_base);
	
	return 0;
fail:
	return retval;
	
}
int buzzer_Release (struct inode *inode, struct file *filp) {
	
	printk("buzzer Release\n");
  return 0;
}

struct file_operations buzzer_fops = {
       read: buzzer_Read,
       write: buzzer_Write,
       open: buzzer_Open,
       release: buzzer_Release,
};

static int __init buzzer_init(void)
{	
	int result;
	
	if (!request_mem_region((unsigned long)BUZZER_REG_BASE, sizeof(BUZZER_REG), "Buzzer Register")) {
		return -EBUSY;
	}
	printk("Got Buzzer Register\n");
	
	buzzer_base = (u32)ioremap((unsigned long)BUZZER_REG_BASE, sizeof(BUZZER_REG));
	
	result = register_chrdev(buzzer_MjNumber, MODULE_NAME, &buzzer_fops);
	if (result < 0) {
		printk("Register Chrdev error\n");
		goto fail;
	}
	
	return 0;
	
fail:
	release_mem_region((unsigned long)BUZZER_REG_BASE, sizeof(BUZZER_REG));
	return -1;
}



static void __exit buzzer_cleanup(void)
{
	unregister_chrdev(buzzer_MjNumber,MODULE_NAME);
	printk("Goodbye buzzer \n");
}


module_init(buzzer_init);
module_exit(buzzer_cleanup);
MODULE_AUTHOR("Shang, Kenny");
MODULE_DESCRIPTION("Buzzer driver for DE2");
MODULE_LICENSE("GPL");
